#!/usr/bin/python
# encoding: utf-8

"""
@file: params_ineqs_funcs.py
@time: 16/9/5 上午11:35
"""
from functools import reduce

# 含参不等式求解

from mathsolver.functions.root.jiefangchenzu import *
from mathsolver.functions.budengshi import common_opers as co
from sympy import solve, expand, simplify, degree, sqrt, factor, var, cancel, fraction, Mul, solveset, Abs
from sympy.sets.fancysets import Reals


class BaseParamerInterval(BaseValue):
    def __init__(self, value):  # {'var':'x', 'paramer_var':'a', 'solveset':((a的取值范围1, x的解集1), (a的取值范围2, x的解集2))}
        self.value = value

    def sympify(self):
        return self.value['solveset']

    def printing(self):
        str_collector = ""
        canshu, var_ = self.value["paramer_var"], self.value["var"]
        for canshu_range, var_range in self.value['solveset']:
            str_collector += "当 %s ∈ %s时，%s ∈ %s \n" % (new_latex(canshu), new_latex(canshu_range), new_latex(var_), new_latex(var_range))
        return str_collector


# 8.已知含参不等式的解集求不等式(求值)
class ParametersInEqs(BaseFunction):
    # 形如a*x**2 + b*x + c
    @staticmethod
    def sym_values_2_eqs(sym_values):
        if co.iterable(sym_values[0]):
            eq_list = []
            for s, v in sym_values:
                eq_list.append([s, v])
            return BaseEqs(eq_list)
        else:
            return BaseEqs([[sym_values[0], sym_values[1]], ])

    @staticmethod
    def union_values(u):
        values = []
        intvls = u.args
        for intv in intvls:
            if intv.left != -S.Infinity:
                values.append(intv.left)
            if intv.right != S.Infinity:
                values.append(intv.right)
        return values

    @staticmethod
    def my_eqs_root(eqs):  # 解决多元相乘不能解的问题
        eq1 = eqs.value[0]
        l1, r1 = eq1
        f1 = l1 - r1
        symbs1 = list(f1.free_symbols)
        eq2 = eqs.value[1]
        l2, r2 = eq2
        f2 = l2 - r2
        symbs2 = list(f2.free_symbols)
        symbs1.extend(symbs2)
        symbs = list(set(symbs1))
        if len(symbs) == 1:
            last_value = list(solveset(f1, domain=S.Reals).intersect(solveset(f2, domain=S.Reals)))[0]
            return symbs[0], last_value
        symb1, symb2 = symbs
        symb1_sub = list(solveset(f1, symbol=symb1))[0]
        f2_sub = f2.subs(symb1, symb1_sub)
        symb2_values = list(solveset(f2_sub, domain=S.Reals))
        symb1_values = map(lambda sv: symb1_sub.subs(symb2, sv), symb2_values)
        return (symb1, symb1_values), (symb2, symb2_values)

    def solver(self, *args):
        ineq = args[0]  # 原不等式
        f, ineq_op, right_e = ineq.sympify()
        f = f - right_e
        a_symbol = list(f.coeff('x**2').free_symbols)[0] if not f.coeff('x**2').is_real else 1
        b_symbol = list(f.coeff('x').free_symbols)[0] if not f.coeff('x').is_real else 1
        tmp_f = f.subs(a_symbol, 1).subs(b_symbol, 1).subs('x', 1)
        c_symbol = list(tmp_f.free_symbols)[0] if not tmp_f.is_real else 1
        dig_p = r'\((-?\d+?)\)'
        if isinstance(args[1], BasePoint):
            point_value = args[1].value
            # conds = [point_value[0], '<', 'x', '<', point_value[1]]
            solution_set = Interval(sympify(point_value[0]), sympify(point_value[1]), left_open=True, right_open=True)
        elif isinstance(args[1], BaseSet):
            if len(args[1].value['conditions']) == 1:
                cond_value = args[1].value['conditions'][0]['ineq']
                solution_set = co.ineq_expr_list_2_interval(cond_value)
            else:
                cond_value1 = args[1].value['conditions'][0]['ineq']
                solution_set1 = co.ineq_expr_list_2_interval(cond_value1)
                cond_value2 = args[1].value['conditions'][1]['ineq']
                solution_set2 = co.ineq_expr_list_2_interval(cond_value2)
                solution_set = solution_set1.union(solution_set2)
        elif isinstance(args[1], BaseInter):
            solution_set = args[1].interval
        else:
            conds = args[1].value['conditions']
            import re
            p = r'\((-?\d+?)\)'
            if len(conds) == 2:
                ineq1 = conds[0]['ineq']
                ineq1 = map(lambda i: re.match(p, i).groups()[0] if re.match(dig_p, i) else i, ineq1)
                ineq2 = conds[1]['ineq']
                ineq2 = map(lambda i: re.match(p, i).groups()[0] if re.match(dig_p, i) else i, ineq2)
                solution_set = co.ineq_expr_list_2_interval(ineq1).union(
                    co.ineq_expr_list_2_interval(ineq2))
                # solution_set = co.ineq_expr_list_2_interval(conds[0]['ineq']).union(
                #     co.ineq_expr_list_2_interval(conds[1]['ineq']))

            else:
                solution_set = co.ineq_expr_list_2_interval(conds[0]['ineq'])
        # solution_set = args[1]  # 解集
        if len(args) == 2:
            # ineqs_list = map(
            #     lambda tmp_ineq: map(lambda i: re.match(dig_p, i).groups()[0] if re.match(p, i) else i, tmp_ineq),
            #     map(lambda c: c['ineq'], conds))
            # x_values = []
            # dig_p2 = '-?\d+'
            # for tmp_ineqs in ineqs_list:
            #     tmp_v = filter(lambda t: re.match(dig_p2, t), tmp_ineqs)[0]
            #     x_values.append(tmp_v)
            if isinstance(solution_set, Interval):
                try:
                    eqs = BaseEqs([[f.subs('x', solution_set.left), 0], [f.subs('x', solution_set.right), 0]])
                    eqs_root = co.eqs_root(eqs)
                except Exception:
                    eqs_root = ParametersInEqs.my_eqs_root(eqs)
                    if len(eqs_root) == 2 and not co.iterable(eqs_root[0]):
                        eqs_root = eqs_root
                    else:
                        s1 = eqs_root[0][0]
                        s1_root = eqs_root[0][1]
                        s1_value = filter(lambda v: v, s1_root)[0]
                        s2_root = eqs_root[1][1]
                        s2 = eqs_root[1][0]
                        s2_value = filter(lambda v: v, s2_root)[0]
                        eqs_root = ((s1, s1_value), (s2, s2_value))
            else:
                x_values = ParametersInEqs.union_values(solution_set)
                tmp_eqs = map(lambda x_v: f.subs('x', sympify(x_v)), x_values)
                tmp_eqs = map(lambda eq_f: [eq_f, 0], tmp_eqs)
                eqs = BaseEqs(tmp_eqs)
                # intv1, intv2 = solution_set.args
                # eqs = BaseEqs([[f.subs('x', intv1.right), 0], [f.subs('x', intv2.left), 0]])
                eqs_root = co.eqs_root(eqs)
            self.steps.append(['由题目可知', eqs.printing()])
            if len(eqs_root) == 2 and not co.iterable(eqs_root[0]):
                eqs_root_print = '%s = %s' % (new_latex(eqs_root[0]), new_latex(eqs_root[1]))
                eqs_root_print = [eqs_root_print, '']
                last_value = BaseSymbolValue({eqs_root[0]: eqs_root[1]})
            else:
                eqs_root_print = map(lambda r: '%s = %s' % (new_latex(r[0]), new_latex(r[1])), eqs_root)
                last_value = BaseSymbolValue(dict(eqs_root))
            self.steps.append(['解得:', ';'.join(eqs_root_print)])
            self.output.append(last_value)
            return self
        target_ineq = args[2]  # 目标不等式
        target_f, target_ineq_op, target_e = target_ineq.sympify()
        target_f = simplify(expand(target_f - target_e))
        # 根据解集的形式决定a的正负
        if ineq_op.find('>') >= 0 and isinstance(solution_set, Union) or ineq_op.find('<') >= 0 and isinstance(
                solution_set,
                Interval):
            a_pm = 1  # 大于0
        else:
            a_pm = -1  # 小于0
        # 确定方程的跟
        if isinstance(solution_set, Union):
            x1, x2 = solution_set.args[0].right, solution_set.args[1].left  # x1 < x2
        else:
            x1, x2 = solution_set.left, solution_set.right
        self.steps.append(['由题意可知: x=%s, x=%s, 是方程%s=0的两根,' % (x1, x2, new_latex(f)),
                           '并且a%s0。' % ('>' if a_pm > 0 else '<')])
        x_square_coeff = f.coeff('x**2')
        x_coeff = f.coeff('x')
        constant = f.as_independent('x')[0]
        # 如果a*x**2 + b*x + c中有一个是可以知道的,那么就可以求出a,b的值
        if x_square_coeff.is_real or x_coeff.is_real or constant.is_real:
            ineqs = BaseEqs([[x1 + x2, -x_coeff / x_square_coeff], [x1 * x2, constant / x_square_coeff]])
            self.steps.append(['由韦达定理可得:', ineqs.printing()])
            sym_values = co.eqs_root(ineqs)
            solves_eqs = ParametersInEqs.sym_values_2_eqs(sym_values)
            self.steps.append(['解得:', solves_eqs.printing()])
            target_f = co.expr_subs(target_f, sym_values)
            self.steps.append(['则目标不等式等价于:%s %s 0' % (new_latex(target_f), target_ineq_op), ''])
            result_interval = solveset(str(target_f) + target_ineq_op + '0', domain=S.Reals)
            self.steps.append(['则目标不等式的解集为:', new_latex(result_interval)])
            self.output.append(BaseSymbolValue({'x': result_interval}))
            return self
        # a*x**2 + b*x + c
        vieta_eqs = BaseEqs([[x1 + x2, -x_coeff / x_square_coeff], [x1 * x2, constant / x_square_coeff]])
        self.steps.append(['由韦达定理可得:', vieta_eqs.printing()])
        target_a_coeff = target_f.coeff('x**2')  # 目标a
        target_b_coeff = target_f.coeff('x')  # 目标b
        target_constant = target_f.as_independent('x')[0]  # 目标c
        self.steps.append(['设方程%s=0的两根分别为m, n,' % new_latex(target_f), ''])
        target_vieta_eqs = BaseEqs(
            [['m+n', -target_b_coeff / target_a_coeff], ['m*n', target_constant / target_a_coeff]])
        self.steps.append(['由韦达定理得:', target_vieta_eqs.printing()])
        a_value = f.coeff('x**2')
        b_value = -(x1 + x2) * a_value
        c_value = x1 * x2 * a_value
        b_sym_value = b_value / co.symbol_coeff(f.coeff('x'))
        c_sym_value = c_value / co.symbol_coeff(f.as_independent('x')[0])
        target_f = co.expr_subs(target_f, ((b_symbol, b_sym_value), (c_symbol, c_sym_value)))
        target_x_square_coeff = target_f.coeff('x**2')  # 目标表达式中x**2的系数
        target_a_pm = target_x_square_coeff.subs(a_symbol, a_pm)
        target_f = simplify(target_f / target_x_square_coeff)
        target_roots = solveset(target_f, domain=S.Reals)
        self.steps.append(['则m, n分别为:', new_latex(target_roots)])
        if target_a_pm < 0:
            target_ineq_op = target_ineq_op.replace('>', '<') if target_ineq_op.find(
                '>') >= 0 else target_ineq_op.replace('<', '>')
        result_interval = solveset(str(target_f) + target_ineq_op + '0', domain=S.Reals)
        self.steps.append(['所以目标不等式的解集为:', new_latex(result_interval)])
        self.output.append(BaseSymbolValue({'x': result_interval}))
        # self.labels.add('已知含参不等式的解集求不等式')
        self.label.add('已知含参不等式的解集求不等式')
        return self


# for step in ParametersInEqs(verbose=True).solver(BaseIneq(['a*x**2 + b*x + c', '>', '0']),
#                                                  BaseSet(['-3', '<', 'x', '<', '-2']),
#                                                  BaseIneq(['a*x**2 - b*x + c', '>', '0'])).steps:
#     print step[0], step[1]
# for step in ParametersInEqs(verbose=True).solver(BaseIneq(['a*x**2 + b*x + c', '>', '0']),
#                                                  BaseSet(['-3', '<', 'x', '<', '-2']),
#                                                  BaseIneq(['a*x**2 - b*x + c', '>', '0'])).steps:
#     print step[0], step[1]

# for step in ParametersInEqs(verbose=True).solver(BaseIneq(['a*x**2 - 5*x + b', '>', '0']), Interval(-3, -2),
#                                                  BaseIneq(['b*x**2 + 5*x + a', '<', '0'])).steps:
#     print step[0], step[1]


# for step in ParametersInEqs(verbose=True).solver(BaseIneq(['a*x**2 + b*x + c', '<', '0']),
#                                                  Interval(-S.Infinity, -2).union(Interval(-1, S.Infinity)),
#                                                  BaseIneq(['c*x**2 + b*x + a', '>', '0'])).steps:
#     print step[0], step[1]

# for step in ParametersInEqs(verbose=True).solver(BaseIneq(['a*x**2 + 5*x - 2', '>', '0']),
#                                                  Interval(sympify('1/2'), 2),
#                                                  BaseIneq(['a*x**2 - 5*x + a**2 - 1', '>', '0'])).steps:
#     print step[0], step[1]


# 9.含参一元二次不等式解法
class ParametersInEqs002(BaseFunction):
    # 分段解集 令 x1<x2
    # a*x**2 + b*x + c
    @staticmethod
    def seg_solveset(seg, f_ineq, a_value, b_value, c_value):
        f_ineq_e_list = co.to_ineq_expr_list(f_ineq)  # 目标不等式
        a_seg_intl = seg[0][2]  # 此时a中未知变量的取值范围
        deta_seg_intl = seg[1][2]  # 此时deta中未知变量的取值范围
        segment_interval = a_seg_intl.intersect(deta_seg_intl)  # 求交集
        if isinstance(segment_interval, EmptySet):  # 如果为空集则不考虑
            return EmptySet()
        a_seg = seg[0][1]  # a的正负情况
        deta_seg = seg[1][1]  # deta正负情况
        f_seg = f_ineq_e_list[1]
        deta_value = seg[1][0]
        steps = []
        if a_seg == 'a>0':
            steps.append(['', ''])
            if deta_seg == 'deta>0':
                x1 = (- b_value - sqrt(deta_value)) / 2 * a_value
                x2 = (- b_value + sqrt(deta_value)) / 2 * a_value
                if f_seg == '>':
                    return Interval(-S.Infinity, x1, right_open=True).union(Interval(x2, S.Infinity, left_open=True))
                else:
                    return Interval(x1, x2, left_open=True, right_open=True)
            elif deta_seg == 'deta=0':
                param_value = solve(deta_value)[0]
                x12 = -b_value / 2 * a_value
                param_symb = list(x12.free_symbols)[0]
                x12 = x12.subs(param_symb, param_value)
                if f_seg == '>':
                    return Interval(-S.Infinity, x12, right_open=True).union(Interval(x12, S.Infinity, left_open=True))
                else:
                    return EmptySet()
            else:  # deta<0
                if f_seg == '>':
                    return S.Reals
                else:
                    return EmptySet()
        elif a_seg == 'a<0':
            if deta_seg == 'deta>0':
                x1 = (-b_value + sqrt(deta_value)) / 2 * a_value
                x2 = (-b_value - sqrt(deta_value)) / 2 * a_value
                if f_seg == '>':
                    return Interval(x1, x2, left_open=True, right_open=True)
                else:
                    return Interval(-S.Infinity, x1, right_open=True).union(Interval(x2, S.Infinity, left_open=True))
            elif seg[1][1] == 'deta=0':
                param_value = solve(deta_value)[0]
                x12 = -b_value / 2 * a_value
                param_symb = list(x12.free_symbols)[0]
                x12 = x12.subs(param_symb, param_value)
                if f_seg == '<':
                    return Interval(-S.Infinity, x12, right_open=True).union(Interval(x12, S.Infinity, left_open=True))
                else:
                    return EmptySet()
            else:  # deta = 0
                if f_seg == '<':
                    return S.Reals
                else:
                    return EmptySet()

    @staticmethod
    def _pretty_print(f_ineq, seg_soul):
        seg = seg_soul[0]
        interval = seg_soul[1]
        if isinstance(interval, Union):
            interval_str = interval
        elif isinstance(interval, FiniteSet):
            interval_str = interval
        elif isinstance(interval, Reals):
            interval_str = 'R'
        else:
            interval_str = new_latex(interval)

    @staticmethod
    def interval_2_print(intl, symb):
        if isinstance(intl, Union):
            return '%s \\in %s' % (new_latex(symb), new_latex(intl))
        if intl.left != -S.Infinity and intl.right != S.Infinity:
            return '%s %s %s %s %s' % (
                intl.left,
                '<' if intl.left_open else '<=', new_latex(symb), '<' if intl.right_open else '<=', intl.right)
        if intl.left != -S.Infinity:
            return '%s %s %s' % (new_latex(symb), '>' if intl.left_open else '<=', new_latex(intl.left))
        else:
            return '%s %s %s' % (new_latex(symb), '<' if intl.right_open else '<=', new_latex(intl.right))

    @staticmethod
    def print_sge_steps(seg):  # 输出每种情况的解题步骤
        steps = []
        # a*x**2 + b*x + c
        a_value = seg[0][0][0]
        a_seg = seg[0][0][1]
        a_intl = seg[0][0][2]
        deta_value = seg[0][1][0]
        if not deta_value.free_symbols:  # 如果deta = 0; 此时b = 0; c = 0    形如 a*x**2 - x
            symb = list(a_value.free_symbols)[0]
        else:
            symb = list(deta_value.free_symbols)[0]
        deta_seg = seg[0][1][1]
        deta_intl = seg[0][1][2]
        result_interval = seg[1]
        if not a_value.is_real:
            steps.append(
                ['当 %s ; %s' % (a_seg.replace('a', new_latex(a_value)), deta_seg.replace('deta', '\\Delta ')), ' '])
            last_interval = a_intl.intersect(deta_intl)
            steps.append(['此时 %s 的取值范围为: ' % new_latex(symb), new_latex(last_interval)])
        else:
            steps.append(['当 %s' % deta_seg.replace('deta', '\\Delta '), ' '])
            steps.append(['此时 %s 的取值范围为: ' % new_latex(symb), new_latex(deta_intl)])
        if isinstance(factor(deta_value), Pow):
            deta_factor = factor(deta_value).args[0]
            # ----deta隐私分解后底数大于0时
            tmp_left_value, tmp_right_value = sympify('0'), sympify('0')
            if isinstance(result_interval, Union):
                first_intl = result_interval.args[0]
                second_intl = result_interval.args[1]
                tmp_first_intl = Interval(first_intl.left, first_intl.right.subs(sqrt(deta_value), deta_factor),
                                          left_open=first_intl.left_open, right_open=first_intl.right_open)
                tmp_second_intl = Interval(second_intl.left.subs(sqrt(deta_value), deta_factor), second_intl.right,
                                           left_open=second_intl.left_open, right_open=second_intl.right_open)
                steps.append(['当 %s > 0 时 即 %s' % (
                    new_latex(deta_factor),
                    ParametersInEqs002.interval_2_print(solveset(deta_factor > 0, domain=S.Reals), symb)),
                              ',不等式的解集范围为: %s ' % new_latex(tmp_first_intl.union(tmp_second_intl))])
                tmp_first_intl = Interval(first_intl.left, first_intl.right.subs(sqrt(deta_value), -deta_factor),
                                          left_open=first_intl.left_open, right_open=first_intl.right_open)
                tmp_second_intl = Interval(second_intl.left.subs(sqrt(deta_value), -deta_factor), second_intl.right,
                                           left_open=second_intl.left_open, right_open=second_intl.right_open)
                steps.append(['当 %s < 0 时 即 %s' % (
                    new_latex(deta_factor),
                    ParametersInEqs002.interval_2_print(solveset(deta_factor < 0, domain=S.Reals), symb)),
                              ',不等式的解集范围为: ' + new_latex(tmp_first_intl.union(tmp_second_intl)) + ';'])
            else:
                if result_interval.left != -S.Infinity:
                    tmp_left_value = result_interval.left.subs(sqrt(deta_value), deta_factor)
                if result_interval.right != S.Infinity:
                    tmp_right_value = result_interval.right.subs(sqrt(deta_value), deta_factor)
                tmp_resut_interval = Interval(tmp_left_value or result_interval.left,
                                              tmp_right_value or result_interval.right,
                                              left_open=result_interval.left_open,
                                              right_open=result_interval.right_open)
                steps.append(['当 %s > 0 时 即 %s' % (
                    new_latex(deta_factor),
                    ParametersInEqs002.interval_2_print(solveset(deta_factor > 0, domain=S.Reals), symb)),
                              ',不等式的解集范围为: %s ' % new_latex(tmp_resut_interval)])
                # -------deta映射分解后底数小于0时------------------
                if result_interval.left != -S.Infinity:
                    tmp_left_value = result_interval.left.subs(sqrt(deta_value), -deta_factor)
                if result_interval.right != S.Infinity:
                    tmp_right_value = result_interval.right.subs(sqrt(deta_value), -deta_factor)
                tmp_resut_interval = Interval(tmp_left_value or result_interval.left,
                                              tmp_right_value or result_interval.right,
                                              left_open=result_interval.left_open,
                                              right_open=result_interval.right_open)
                steps.append(['当 %s < 0 时 即 %s' % (
                    new_latex(deta_factor),
                    ParametersInEqs002.interval_2_print(solveset(deta_factor < 0, domain=S.Reals), symb)),
                              ',不等式的解集范围为: ' + new_latex(tmp_resut_interval) + ';'])
        else:
            steps.append(['解的不等式的解集范围为: %s ;' % new_latex(result_interval), ''])
        return steps

    def solver(self, *args):
        # a*x**2 + b*x + c
        self.label.add('解含参数一元二次不等式')
        ineq = args[0]
        f, ineq_op, right_hand = ineq.sympify()
        f1 = f - right_hand
        x_symbol = sympify('x')
        other_symbol = list(sympify(f1).free_symbols - set([x_symbol, ]))[0]
        if not fraction(cancel(f))[1].is_real:  # 如果是含分式的
            left_hand = cancel(f - right_hand)
            left_frac = fraction(cancel(left_hand))
            self.steps.append(['原不等式移项变形得: ', new_latex(left_hand) + ineq_op + '0'])
            f = left_frac[0] * left_frac[1]
            self.steps.append(['等价于 ' + new_latex(f) + ineq_op + '0', ''])
        else:
            f = f - right_hand
        f = expand(f)
        param_symb = filter(lambda s: str(s) != 'x', list(f.free_symbols))[0]
        a_value = f.coeff('x**2')
        if not a_value:
            raise Exception('Type Match Error')
        b_value = f.coeff('x')
        c_value = f.as_independent('x')[0]
        deta = b_value ** 2 - 4 * a_value * c_value
        a_zero_seg = ()
        if not a_value.is_real:  # 当a的值含有参数,此时讨论a=0的情况
            solve_value = list(solveset(a_value, domain=S.Reals))
            if solve_value:
                param_value = list(solveset(a_value, domain=S.Reals))[0]
                self.steps.append(['当 %s = 0' % new_latex(a_value), '时'])
                tmp_f = f.subs(param_symb, param_value)
                result_interval = solveset(str(tmp_f) + ineq_op + '0', domain=S.Reals)
                self.steps.append(['原不等式为:', new_latex(tmp_f) + ineq_op + '0'])
                self.steps.append(['此时求的不等式的解集为:', new_latex(result_interval) + ';'])
                a_zero_seg = (FiniteSet(param_value), result_interval)
        a_segs = [(a_value, 'a>0', co.solve_expr(a_value > 0)),
                  (a_value, 'a<0', co.solve_expr(a_value < 0))]  # a分段讨论
        deta_segs = ((deta, 'deta>0', co.solve_expr(deta > 0)), (deta, 'deta<0', co.solve_expr(deta < 0)),
                     (deta, 'deta=0', co.solve_expr('%s=0' % str(deta))))  # deta分段讨论
        segs = co.combin_iters(a_segs, deta_segs)
        segs_sets = map(
            lambda tmp_seg: (tmp_seg,
                             ParametersInEqs002.seg_solveset(tmp_seg, 'f(x)' + ineq_op + '0', a_value, b_value,
                                                             c_value)),
            segs)  # 两两组合分段讨论

        result_segments = filter(lambda seg_interv: seg_interv[1], segs_sets)
        for rs in result_segments:
            ParametersInEqs002._pretty_print('f(x)' + ineq_op + '0', rs)
        # assert result_segments, "failed"
        # -------------输出解题步骤--------------------------
        # self.steps.append(['由题目可知 \Delta = ' + latex(deta), ''])
        # self.output.append(BaseNumber('1'))
        # self.steps.append()
        for seg in result_segments:
            self.steps.extend(ParametersInEqs002.print_sge_steps(seg))
        # self.output.append()
        # ---------输出解题结果--------------------
        output_value = {'var': x_symbol, 'paramer_var': other_symbol, 'solveset': []}
        if a_zero_seg:
            output_value['solveset'].append(a_zero_seg)
        for parm_intl, result_intl in result_segments:
            tmp_parm_intl = parm_intl[0][-1].intersect(parm_intl[1][-1])
            output_value['solveset'].append((tmp_parm_intl, result_intl))
        self.output.append(BaseParamerInterval(output_value))
        return self


# for step in ParametersInEqs002(verbose=True).solver(BaseIneq(['a*x / (x - 1)', '>', '1'])).steps:
#     print step[0], step[1]

# for step in ParametersInEqs002(verbose=True).solver(BaseIneq(['(x-1)*(a*x+a-1)', '<', '0'])).steps:
#     print step[0], step[1]

# for step in ParametersInEqs002(verbose=True).solver(BaseIneq(['(a*x+1)*(x-1)', '>', '0'])).steps:
#     print step[0], step[1]
# for step in ParametersInEqs002(verbose=True).solver(BaseIneq(['2*x**2 + a*x + 2', '>', '0'])).steps:
#     print step[0], step[1]

# for step in ParametersInEqs002(verbose=True).solver(BaseIneq(['(m**2 + 1)*x**2 - 4*x + 1', '>', '0'])).steps:
#     print step[0], step[1]

# for step in ParametersInEqs002(verbose=True).solver(BaseIneq(['x**2 - 5*a*x + 6*a**2', '>', '0'])).steps:
#     print step[0], step[1]

# for step in ParametersInEqs002(verbose=True).solver(BaseIneq(['(a*x + 1)*(x-1)', '>', '0'])).steps:
#     print step[0], step[1]


# for step in ParametersInEqs002(verbose=True).solver(BaseIneq(['(x - a)*(x- 1 + a)', '<', '0'])).steps:
#     print step[0], step[1]


# 11.解多项式不等式
class MultiIneq(BaseFunction):
    def solver(self, *args):
        ineq = args[0]
        left, ineq_op, right = ineq.sympify()
        f = left - right
        f = factor(expand(f))
        # 换成标准式子
        f_coeff = f.as_coefficients_dict().values()[0]
        if f_coeff > 0:
            f = f / f_coeff
        else:
            f = f / f_coeff
            ineq_op = ineq_op.replace('>', '<') if ineq_op.find('>') >= 0 else ineq_op.replace('>', '<')
        f_ineq = BaseIneq([f, ineq_op, '0'])
        self.steps.append(['换成标准形式:', f_ineq.printing()])
        f_solveset = solveset(f, domain=S.Reals)
        self.steps.append(['令%s=0' % str(f), '解的x的解集为:' + str(f_solveset)])
        self.steps.append(['由穿线法可得: 解集为:', solveset(str(f) + ineq_op + '0', domain=S.Reals)])
        self.label.add('解多项式不等式')
        return self


# for step in MultiIneq(verbose=True).solver(BaseIneq(['(x-1)*(1-x**2)*(x-2)', '>', '0'])).steps:
#     print step[0], step[1]


# 12.一元二次不等式的解法
class QuadIneq(BaseFunction):
    @staticmethod
    # 规范化处理
    def stand_ineq(ineq):
        left, ineq_s, right = ineq.sympify()
        f = factor(left - right)
        x_symbol = list(f.free_symbols)[0]
        if isinstance(f, Mul):  # 如果可以因式分解
            f_coeff = f.as_independent(x_symbol)[0]
            if f_coeff > 0:
                f = f / f_coeff
            else:
                f = f / f_coeff
                ineq_s = ineq_s.replace('>', '<') if ineq_s.find('>') >= 0 else ineq_s.replace('<', '>')
        else:  # 如果不可以因式分解
            x_deg = degree(f)
            x_deg_coeff = f.coeff(pow(x_symbol, x_deg))
            if x_deg_coeff < 0:
                f = f / sympify(-1)
                ineq_s = ineq_s.replace('>', '<') if ineq_s.find('>') >= 0 else ineq_s.replace('<', '>')
        return BaseIneq([f, ineq_s, 0])

    def solver(self, *args):
        ineq = args[0]
        prev_left, prev_ineq, prev_right = ineq.sympify()
        ineq = QuadIneq.stand_ineq(ineq)
        left, ineq_s, zero = ineq.sympify()
        if ineq_s != prev_ineq:
            prev_f = prev_left - prev_right
            x_symbol = list(prev_f.free_symbols)[0]
            f_d = degree(prev_f)
            f_coeff = prev_f.coeff(pow(x_symbol, f_d))
            if f_coeff < 0:
                prev_f = prev_f / sympify(-1)
                prev_ineq = prev_ineq.replace('>', '<') if prev_ineq.find('>') >= 0 else prev_ineq.replace('<', '>')
            prev_f_ineq = BaseIneq([prev_f, prev_ineq, 0])
            self.steps.append(['不等式规范化处理得:', prev_f_ineq.printing()])
        if isinstance(left, Mul):  # 如果可因式分解
            self.steps.append(['不等式因式分解得:', ineq.printing()])
        else:  # 不可因式分解
            self.steps.append(['求出方程%s=0的根为:%s' % (left, new_latex(solveset(left, domain=S.Reals)))])
        self.steps.append(['综述原不等式的解集为:', new_latex(solveset(left, domain=S.Reals))])
        self.label.add('一元二次不等式的解法')
        return self


# for step in QuadIneq(verbose=True).solver(BaseIneq(['0', '<', '-x**2 + 3*x + 10'])).steps:
#     print step[0], step[1]


# 13.待定系数法求不等式范围

class CoeffIneq(BaseFunction):
    _latters = [chr(ord('a') + i) for i in range(0, 26)]

    @staticmethod
    def _unique_symbs(symbs, n):  # 获取 N个不重复的符号变量
        import random
        u_symbs = []
        symb_strs = [str(i) for i in symbs]
        while n:
            sym = CoeffIneq._latters[random.randint(0, 25)]
            if sym not in symb_strs and sym not in u_symbs:
                u_symbs.append(sym)
                n -= 1
        return u_symbs

    @staticmethod
    def expr_replace(e, symb_values):  # 替换不等式中的符号, 因为sympy 中subs 函数 回自动化简, 所以只能做字符串替换
        e = str(e)
        for s, v in symb_values.items():
            e = e.replace(str(s), str(v))
        return e

    def solver(self, *args):
        # ineqs = args[0].sympify()
        ineqs = [co.to_ineq_expr_list(ineq) for ineq in args[0]]
        ineqs = map(co.stand_ineq_expr_list, ineqs)
        target_f = args[1].sympify()  # 目标表达式
        # symbs代表不等式中由那些符号变量, 主要是为了避免待定系数变量的符号与不等式中的符号变量产生冲突
        symbs = co.flatten(
            [sympify(ineq[2] if len(ineq) == 5 else ineq[0]).free_symbols for ineq in
             ineqs])
        symbs = list(set(map(lambda sym: str(sym), symbs)))
        # 待定系数的符号变量
        coeff_symbs = CoeffIneq._unique_symbs(symbs, len(ineqs))
        coeff_f = sympify('0')
        coeff_dict = {}
        for coeff, ineq in zip(coeff_symbs, ineqs):
            coeff_f += var(coeff) * sympify(ineq[2] if len(ineq) == 5 else ineq[0])
            coeff_dict[coeff] = ineq
        self.steps.append(['解:', BaseEq([target_f, coeff_f]).printing()])
        mul_coeff = coeff_f  # 整体代换形式, 形如m*(a + b) + n*(a - b)
        coeff_f = expand(coeff_f)
        coeff_eqs = []
        for symb in symbs:
            coeff_eqs.append(BaseEq([coeff_f.coeff(symb), target_f.coeff(symb)]))
        self.steps.append(['$$\because $$:', co.to_bases(coeff_eqs, BaseEqs).printing()])
        coeff_values = map(lambda sv: (str(sv[0]), sv[1]), co.eqs_root(coeff_eqs))
        self.steps.append(['$$\therefore $$:', co.to_bases(coeff_values, BaseEqs).printing()])
        coeff_values_dict = dict(coeff_values)
        intervals = []
        for coeff, value in coeff_values_dict.items():
            interv = co.ineq_expr_list_2_interval(coeff_dict[coeff])
            intervals.append(co.interval_mul_rel(interv, value))
        # print coeff_values_dict, mul_coeff
        self.steps.append(
            ['$$\therefore $$:' + new_latex(target_f),
             '=' + new_latex(CoeffIneq.expr_replace(mul_coeff, coeff_values_dict))])
        result_interval = reduce(co.two_interval_add, intervals)
        self.steps.append(['则%s的取值范围为:%s' % (new_latex(target_f), new_latex(result_interval)), ''])
        # print intervals, reduce(co.two_interval_add, intervals)
        self.output.append(co.to_base_interval(result_interval))
        self.label.add('待定系数法求不等式范围')
        return self


# for step in CoeffIneq(verbose=True).solver(
#         ['-1<a+b<3', '2<a-b<4'], BasePoly('2*a + 3*b')).steps:
#     print step[0], step[1]


# for step in CoeffIneq(verbose=True).solver(
#         ['a+b<=5', '-1<=a-b<=3'], BasePoly('3*a - b')).steps:
#     print step[0], step[1]


# for step in CoeffIneq(verbose=True).solver(
#         ['-1<a+b<3', '2<a-b<4'], BasePoly('2*a + 3*b')).steps:
#     print step[0], step[1]


# 15.已知绝对值不等式的解集求参数的值
class ParamAbsedIneq(BaseFunction):
    @staticmethod
    def _split_absed_e(f):
        absed = sympify('0')
        other = sympify('0')
        for m, c in f.as_coefficients_dict().items():
            if isinstance(m, Abs):
                absed += m * c
            else:
                other += m * c
        return absed, other

    @staticmethod
    def solve_param_ineq(param_ineq):
        pass

    def solver(self, *args):
        left_hand, ineq_op, right_hand = args[0].sympify()
        ineq_solvset_value = args[1].value
        p = '(-?\\d+/?\\d*)'
        left = sympify(re.findall(p, ineq_solvset_value[0])[0])
        right = sympify(re.findall(p, ineq_solvset_value[1])[0])
        ineq_solvset = Interval(left, right, left_open=True, right_open=True)
        left_value, right_value = ineq_solvset.left, ineq_solvset.right
        w = left_hand - right_hand
        f, other = ParamAbsedIneq._split_absed_e(w)
        g = -other
        segs_sets = co.solve_param_absed_ineq(f, ineq_op, g)
        # --------输出-------------
        self.steps.append(['因为:' + args[0].printing(), ''])
        if ineq_op.find('<') >= 0:
            self.steps.append(['所以:%s < %s < %s' % (new_latex(-g), new_latex(f.args[0]), new_latex(g)), ''])
        else:
            self.steps.append(
                ['所以:%s > %s;' % (new_latex(f.args[0]), new_latex(g)), '; %s < %s' % (new_latex(f.args[0]), new_latex(-g))])
        self.steps.append(['已知原不等式的解集为 ' + new_latex(ineq_solvset), ', 所以有:'])
        if isinstance(ineq_solvset, Interval):
            if co.iterable(segs_sets):  # 如果是分段讨论的话
                for seg in segs_sets:
                    self.steps.append(['当:' + seg[0] + ', x 取值范围为:' + new_latex(seg[-1]), ''])
                    seg1_eqs = BaseEqs([[seg[-1].left, left_value], [seg[-1].right, right_value]])
                    seg1_eqs_root = co.eqs_root(seg1_eqs)
                    if not seg1_eqs_root:
                        self.steps.append([seg1_eqs.printing(), '此方程无解(舍去)。'])
                    else:
                        if isinstance(seg1_eqs_root, tuple):
                            self.steps.append(['解得 %s = %s' % (seg1_eqs_root[0], seg1_eqs_root[1]), ''])
                            self.output.append(BaseSymbolValue({seg1_eqs_root[0]: seg1_eqs_root[1]}))
        else:
            assert "try fail"
        self.label.add('已知绝对值不等式的解集求参数的值')
        return self

# for step in ParamAbsedIneq().solver(BaseIneq(['Abs(a*x + 2)', '<', '4']), Interval(-1, 3)).steps:
#     print step[0], step[1]
